(function($, gmwk) {

    function API(Options) {
  
        // console.info("Options", Options);
        
        var self = this;
        var sClassName = Options.sClassName;
        
        // Data store
        this.Quotes = function() { return Quotes; }  // This function is only for debugging
        var Quotes = {
            Data: {
                aQuotes : [
                    {
                        sQuote: "A computer once beat me at chess, but it was no match for me at kick boxing.",
                        sAuthor: "Emo Philips"
                    },
                    {
                        sQuote: "Computer Science is no more about computers than astronomy is about telescopes.",
                        sAuthor: "Edsger W. Dijkstra"
                    },
                    {
                        sQuote: "Software is a gas; it expands to fill its container.",
                        sAuthor: "Nathan Myhrvold"
                    },
                    {
                        sQuote: "All parts should go together without forcing.  You must remember that the parts you are reassembling were disassembled by you.  Therefore, if you can't get them together again, there must be a reason.  By all means, do not use a hammer.",
                        sAuthor: "IBM Manual, 1925"
                    },
                    {
                        sQuote: "Physics is the universe's operating system.",
                        sAuthor: "Steven R Garman"
                    },
                    {
                        sQuote: "It's hardware that makes a machine fast.  It's software that makes a fast machine slow.",
                        sAuthor: "Craig Bruce"
                    },
                    {
                        sQuote: "The greatest enemy of knowledge is not ignorance, it is the illusion of knowledge.",
                        sAuthor: "Stephen Hawking"
                    },
                    {
                        sQuote: "Tell me and I forget.  Teach me and I remember.  Involve me and I learn.",
                        sAuthor: "Benjamin Franklin"
                    },
                    {
                        sQuote: "If people never did silly things, nothing intelligent would ever get done.",
                        sAuthor: "Ludwig Wittgenstein"
                    },
                    {
                        sQuote: "Getting information off the Internet is like taking a drink from a fire hydrant.",
                        sAuthor: "Mitchell Kapor"
                    },
                    {
                        sQuote: "If you think your users are idiots, only idiots will use it.",
                        sAuthor: "Linus Torvalds"
                    },
                    {
                        sQuote: "Where is the 'any' key?",
                        sAuthor: "Homer Simpson, in response to the message, 'Press any key'"
                    },
                    {
                        sQuote: "The Internet?  We are not interested in it.",
                        sAuthor: "Bill Gates, 1993"
                    },
                    {
                        sQuote: "If you think you are worth what you know, you are very wrong.  Your knowledge today does not have much value beyond a couple of years.  Your value is what you can learn and how easily you can adapt to the changes this profession brings so often.",
                        sAuthor: "Jose M. Aguilar"
                    },
                    {
                        sQuote: "Programs must be written for people to read, and only incidentally for machines to execute.",
                        sAuthor: "Abelson and Sussman"
                    },
                    {
                        sQuote: "Before software should be reusable, it should be usable.",
                        sAuthor: "Ralph Johnson"
                    },
                    {
                        sQuote: "Make everything as simple as possible, but not simpler.",
                        sAuthor: "Albert Einstein"
                    },
                    {
                        sQuote: "If the code and the comments do not match, possibly both are incorrect.",
                        sAuthor: "Norm Schryer"
                    },
                    {
                        sQuote: "Manually managing blocks of memory in C is like juggling bars of soap in a prison shower: It's all fun and games until you forget about one of them.",
                        sAuthor: "anonymous Usenet user"
                    },
                    {
                        sQuote: "There are only two things wrong with C++:  The initial concept and the implementation.",
                        sAuthor: "Bertrand Meyer"
                    },
                    {
                        sQuote: "It was a joke, okay?  If we thought it would actually be used, we wouldn't have written it!",
                        sAuthor: "Mark Andreesen, speaking of the HTML tag BLINK"
                    },
                    {
                        sQuote: "Passwords are like underwear: you don't let people see it, you should change it very often, and you shouldn't share it with strangers.",
                        sAuthor: "Chris Pirillo "
                    },
                    {
                        sQuote: "Yes, we have a dress code. You have to dress.",
                        sAuthor: "Scott McNealy, co-founder of Sun Microsystems"
                    },
                    {
                        sQuote: "Two years from now, spam will be solved.",
                        sAuthor: "Bill Gates, 2004"
                    },
                    {
                        sQuote: "I see little commercial potential for the Internet for at least ten years.",
                        sAuthor: "Bill Gates, 1994"
                    }
                ]
            }
        }
    
        this.Contacts = function() { return Contacts; }
        var Contacts = {
            Data: {
                aContacts: [
                    {
                        nCID: 1,
                        sName: "John",
                        sLastName: "Doe"
                    },
                    {
                        nCID: 2,
                        sName: "Joe",
                        sLastName: "Soap"
                    }
                ]
            }
        }
        
        this.Contact = function() { return Contact; }
        var Contact = {
            Data: {
                aContact: [
                    {
                        nCID: 0,
                        sName: "",
                        sLastName: ""
                    }
                ]
            }
        }
        
        this.Tasks = function() { return Tasks; }
        var Tasks = {
            Data: {
                aTasks: [
                    {
                        nCID: 1,
                        sHeading: "Task 1",
                        sDescription: "Write framework"
                    },
                    {
                        nCID: 2,
                        sHeading: "Task 2",
                        sDescription: "Drink beer"
                    }
                ]
            }
        }
        
        this.Task = function() { return Task; }
        var Task = {
            Data: {
                aTask: [
                    {
                        nCID: 0,
                        sHeading: "",
                        sDescription: ""
                    }
                ]
            }
        }
        
        // console.info("---------> API constructed");
    
        this.getClassName = function() {
            return sClassName;
        }
        
        this.request = function(sRequest, Options, fCallback) {
            // Set params
            if (Options.jqForm !== undefined) {
                Options.Params = Options.jqForm.serializeObject();
            } else if (Options.Params === undefined) {
                Options.Params = {};
            }
            // Simulate server request
            var sClassName;
            var sMethod;
            var aRequest = sRequest.split("/");
            sClassName = aRequest[0];
            sMethod = aRequest[1];
            //[sClassName, sMethod] = sRequest.split("/"); // Only works in Firefox... why do other browsers suck so much?
            var sFunction = "f" + sClassName;
            var sCommand = sFunction + '("' + sMethod + '", ' + JSON.stringify(Options.Params) + ')';
            if (eval("typeof " + sFunction + " !== 'undefined'")) {
                var Response = eval(sCommand);
                if (Response.bSuccess) {
                    fCallback(Response.Data);
                } else {
                    if (Options.fError !== undefined) {
                        Options.fError(Response.Error);
                    } else {
                        alert("Error: " + Response.Error.nCode + " Message: " + Response.Error.sMessage);
                    }
                }
            }
        }
        
        function fContact(sMethod, Params) {
            var Response = {
                bSuccess: true,
                Error: {},
                Data: {}
            }
            switch (sMethod) {
              case "list":
                  // Object assignment is by reference, return a copy to protect source data!
                  $.extend(true, Response.Data, Contacts.Data);
                  return Response;
                  break;
              case "details":
                  Response.Data.aContact = [{}];
                  for (var n = 0; n < Contacts.Data.aContacts.length; n++) {
                      if (Contacts.Data.aContacts[n].nCID === Params.nCID) {
                          $.extend(true, Response.Data.aContact[0], Contacts.Data.aContacts[n]);
                          return Response;
                      }
                  }
                  // Not found
                  Response.bSuccess = false;
                  Response.Error = {
                      nCode: 100,
                      sMessage: "Contact not found"
                  }
                  return Response;
                  break;
              case "save":
                  var nCID = parseInt(Params.nCID, 10);
                  nCID = isNaN(nCID) ? 0 : nCID;
                  // Add
                  if (nCID === 0) {
                      Params.nCID = Contacts.Data.aContacts.length + 1;
                      Contacts.Data.aContacts.push(Params);
                      return Response;
                  }
                  // Update
                  for (var n = 0; n < Contacts.Data.aContacts.length; n++) {
                      if (Contacts.Data.aContacts[n].nCID === nCID) {
                          Contacts.Data.aContacts[n].sName = Params.sName;
                          Contacts.Data.aContacts[n].sLastName = Params.sLastName;
                          return Response;
                      }
                  }
                  // Not found
                  Response.bSuccess = false;
                  Response.Error = {
                      nCode: 100,
                      sMessage: "Contact not updated, could not be found"
                  }
                  return Response;
                  break;
              case "delete":
                  var nCID = parseInt(Params.nCID, 10);
                  nCID = isNaN(nCID) ? 0 : nCID;
                  // delete
                  for (var n = 0; n < Contacts.Data.aContacts.length; n++) {
                      if (Contacts.Data.aContacts[n].nCID === nCID) {
                          Contacts.Data.aContacts.splice(n, 1);
                          return Response;
                      }
                  }
                  // Not found
                  Response.bSuccess = false;
                  Response.Error = {
                      nCode: 100,
                      sMessage: "Contact not deleted, could not be found"
                  }
                  return Response;
                  break;
            }
        }
    
        function fTask(sMethod, Params) {
            var Response = {
                bSuccess: true,
                Error: {},
                Data: {}
            }
            switch (sMethod) {
              case "list":
                  // Object assignment is by reference, return a copy to protect source data!
                  $.extend(true, Response.Data, Tasks.Data);
                  return Response;
                  break;
              case "details":
                  Response.Data.aTask = [{}];
                  for (var n = 0; n < Tasks.Data.aTasks.length; n++) {
                      if (Tasks.Data.aTasks[n].nCID === Params.nCID) {
                          $.extend(true, Response.Data.aTask[0], Tasks.Data.aTasks[n]);
                          return Response;
                      }
                  }
                  // Not found
                  Response.bSuccess = false;
                  Response.Error = {
                      nCode: 100,
                      sMessage: "Task not found"
                  }
                  return Response;
                  break;
              case "save":
                  var nCID = parseInt(Params.nCID, 10);
                  nCID = isNaN(nCID) ? 0 : nCID;
                  // Add
                  if (nCID === 0) {
                      Params.nCID = Tasks.Data.aTasks.length + 1;
                      Tasks.Data.aTasks.push(Params);
                      return Response;
                  }
                  // Update
                  for (var n = 0; n < Tasks.Data.aTasks.length; n++) {
                      if (Tasks.Data.aTasks[n].nCID === nCID) {
                          Tasks.Data.aTasks[n].sHeading = Params.sHeading;
                          Tasks.Data.aTasks[n].sDescription = Params.sDescription;
                          return Response;
                      }
                  }
                  // Not found
                  Response.bSuccess = false;
                  Response.Error = {
                      nCode: 100,
                      sMessage: "Task not updated, could not be found"
                  }
                  return Response;
                  break;
              case "delete":
                  var nCID = parseInt(Params.nCID, 10);
                  nCID = isNaN(nCID) ? 0 : nCID;
                  // delete
                  for (var n = 0; n < Tasks.Data.aTasks.length; n++) {
                      if (Tasks.Data.aTasks[n].nCID === nCID) {
                          Tasks.Data.aTasks.splice(n, 1);
                          return Response;
                      }
                  }
                  // Not found
                  Response.bSuccess = false;
                  Response.Error = {
                      nCode: 100,
                      sMessage: "Task not deleted, could not be found"
                  }
                  return Response;
                  break;
            }
        }
        
        function fQuote(sMethod, Params) {
            var Response = {
                bSuccess: true,
                Error: {},
                Data: {}
            }
            switch (sMethod) {
                case "list":
                    var nQuotes = 0;
                    var Index = {};
                    Response.Data.aQuotes = [];
                    while (nQuotes < 5) { // Amount of quotes to return
                        nRand = Math.random();
                        nIndex = Math.floor(nRand * Quotes.Data.aQuotes.length);
                        if (Index[nIndex] === undefined) { // Make sure we return unique quotes
                            Response.Data.aQuotes.push($.extend(true, {}, Quotes.Data.aQuotes[nIndex]));
                            Index[nIndex] = true;
                            nQuotes++;
                        }
                    }
                    return Response;
                    break;
            }
        }
    
    }
  
    gmwk.classes.API = API;

})(jQuery, window.gmwk);
